<?php

/*
 * This file is part of the slince/dragbox package.
 *
 * (c) Slince <taosikai@yeah.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace DragBox\Common\Filesystem;

use DragBox\Common\Filesystem\Exception\FileNotExistsException;
use DragBox\Common\Filesystem\Index\IndexerInterface;
use Symfony\Component\Finder\Finder;

class Filesystem implements FilesystemInterface
{
    /**
     * @var string
     */
    protected $path;

    /**
     * @var IndexerInterface
     */
    protected $indexer;

    /**
     * @var Finder
     */
    protected $finder;

    public function __construct(
        $path,
        IndexerInterface $indexer,
        Finder $finder = null
    ) {
        $this->path = $path;
        $this->indexer = $indexer;
        $this->finder = $finder ?: new Finder();
    }

    /**
     * {@inheritdoc}
     */
    public function index()
    {
        $this->finder->files()->in($this->path);
        $files = [];
        foreach ($this->finder as $fileInfo) {
            $files[] = FileFactory::createByFileInfo($fileInfo);
        }
        $this->indexer->index($files);
    }

    /**
     * {@inheritdoc}
     */
    public function find($key)
    {
        return $this->indexer->find($key);
    }

    /**
     * {@inheritdoc}
     */
    public function createStream($key, $mode = 'r')
    {
        $file = $this->find($key);
        if ($file === null) {
            if ($mode{0} === 'r') {
                throw new FileNotExistsException($key);
            } else {
                $file = FileFactory::createBlankFile($key);
            }
        }
        $resource = fopen($file->getPathname(), $mode);
        return $resource;
    }

    /**
     * {@inheritdoc}
     */
    public function queryStates($files)
    {
        $persistedFiles = $this->indexer->findAll(array_column($files, 'key'));
        foreach ($files as $file) {
            $key = $file->getKey();
            if (!isset($persistedFiles[$key])) {
                $file->setParameter('state', FileInterface::STATE_MISSING);
                continue;
            }
            $dstFile = $persistedFiles[$key];
            if ($dstFile->getHash() === $file->getHash()) {
                $file->setParameter('state', FileInterface::STATE_NO_CHANGE);
                continue;
            }
            if ($dstFile->getUpdatedAt() > $file->getUpdatedAt()) {
                $fileData['state'] = FileInterface::STATE_OUTDATE;
                $file->setParameter('state', FileInterface::STATE_OUTDATE);
            } else {
                $file->setParameter('state', FileInterface::STATE_FRESH);
            }
        }
        return $files;
    }
}